package org.elephas.webapp.application;

import java.util.Iterator;

import javax.servlet.http.Cookie;

import org.apache.wicket.Request;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.Session;
import org.apache.wicket.injection.web.InjectorHolder;
import org.apache.wicket.protocol.http.WebRequest;
import org.apache.wicket.protocol.http.WebResponse;
import org.apache.wicket.protocol.http.WebSession;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.elephas.model.Blog;
import org.elephas.model.BlogMembership;
import org.elephas.model.BlogRole;
import org.elephas.model.User;
import org.elephas.service.UserFinder;

/**
 * Use this session to check whether the current user is logged in and to
 * retrieve the current {@link User} object. <br/>
 *
 * On construction this session tries to find a userId in the cookies to
 * automatically restore the last logged in user.
 *
 * TODO: figure out where to set the cookie (eg. here, LoginPage, ...)
 *
 * @author Gerolf Seitz
 * 
 */
public class ElephasSession extends WebSession {
	private static final long serialVersionUID = 1L;

	private static final String USER_ID_COOKIE_NAME = "elephas:userId";

	private String userId;
	private transient User user;

	@SpringBean
	private UserFinder userFinder;

	/**
	 * Constructs.
	 *
	 * @param request
	 *            the request
	 */
	public ElephasSession(Request request) {
		super(request);
		userId = readUserIdFromCookies(request);

		InjectorHolder.getInjector().inject(this);
	}

	/**
	 * Tries to read the userId off the request's cookies.
	 *
	 * @param request
	 *            the request
	 * @return either the userId or null if the right cookie is not available
	 */
	private String readUserIdFromCookies(Request request) {
		Cookie cookie = ((WebRequest) request).getCookie(USER_ID_COOKIE_NAME);
		return cookie == null ? null : cookie.getValue();
	}

	/**
	 * Stores the current userId in a cookie.
	 */
	private void setUserCookie() {
		Cookie cookie = new Cookie(USER_ID_COOKIE_NAME, userId);
		((WebResponse) RequestCycle.get().getResponse()).addCookie(cookie);
	}

	private void removeUserCookie() {
		Cookie cookie = ((WebRequest) RequestCycle.get().getRequest())
				.getCookie(USER_ID_COOKIE_NAME);
		((WebResponse) RequestCycle.get().getResponse()).clearCookie(cookie);
	}

	/**
	 * Sets the user.
	 *
	 * @param toSet
	 *            the user
	 */
	public synchronized void setUser(User toSet) {
		this.user = toSet;
		userId = toSet == null ? null : toSet.getEmailAddress();
	}

	/**
	 * Returns null if the user is not logged in. Otherwise returns the
	 * currently logged in user by either returning the cached {@link User}
	 * object or by loading it from the database.
	 *
	 * @return the currently logged in user or null
	 */
	public synchronized User getUser() {
		if (user == null) {
			if (userId != null) {
				user = userFinder.findByEmail(userId);
			}
		}
		return user;
	}

	public BlogRole getUserRole(Blog blog) {
		if (isSignedIn() && blog != null) {
			return blog.getBlogRoleForUser(getUser());
		}
		return null;
	}

	/**
	 * Checks if the current user is logged in.
	 *
	 * @return true if the user is logged in, false otherwise
	 */
	public boolean isSignedIn() {
		return getUser() != null;
	}

	/**
	 * Signs the user in.
	 *
	 * @param email
	 *            the user's email address
	 * @param password
	 *            the user's password
	 * @return true if the authentication was successful, false otherwise
	 */
	public boolean signIn(String email, String password) {
		User loggingIn = userFinder.findByEmail(email);
		if (loggingIn != null && loggingIn.getPassword().equals(password)) {
			setUser(loggingIn);
			setUserCookie();
			return true;
		}
		return false;
	}

	public void signOut() {
		setUser(null);
		removeUserCookie();
	}

	@Override
	protected void detach() {
		super.detach();
		user = null;
	}

	/**
	 * @return the {@link ElephasSession} instance
	 */
	public static ElephasSession get() {
		return (ElephasSession) Session.get();
	}

    public boolean isBlogAdmin(Blog blog) {
        Iterator<BlogMembership> blogs = getUser().getBlogs().iterator();
        boolean isAdmin = false;
        while(!isAdmin && blogs.hasNext()) {
            BlogMembership membership = blogs.next();
            isAdmin = membership.getBlog().equals(blog) && membership.getBlogRole().implies(BlogRole.BLOG_ADMIN);
        }
        return isAdmin;
    }
}
